#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shm_com_sem.h"

int main(void)
{
    void *shared_memory = (void *)0;    // 共享内存（a缓冲区指针）
    struct shared_mem_st *shared_stuff; // 将无类型共享存储区转换为shared_mem_st类型的指针
    char key_line[256];

    int shmid; // 共享内存id

    sem_t *sem_queue, *sem_queue_empty, *sem_queue_full; // 访问共享内存的互斥量、空缓冲区、满缓冲区信号量
    // 获取共享内存区，并挂入内存
    if ((shmid = shmget(SHM_KEY, sizeof(struct shared_mem_st), IPC_CREAT | 0666)) < 0)
    {
        perror("shmget fail!\n");
        exit(1);
    }
    if ((shared_memory = shmat(shmid, (void *)0, 0)) == (void *)-1)
    {
        perror("shmat fail!\n");
        exit(1);
    }

    shared_stuff = (struct shared_mem_st *)shared_memory; // 将缓冲区指针转换为shared_mem_st类型

    // 下面创建三个信号量
    sem_queue = sem_open(queue_mutex, O_CREAT, 0644, 1);
    if (sem_queue == SEM_FAILED)
    {
        perror("sem_open queue_mutex fail!\n");
        exit(EXIT_FAILURE);
    }
    sem_queue_empty = sem_open(queue_empty, O_CREAT, 0644, NUM_LINE);
    if (sem_queue_empty == SEM_FAILED)
    {
        perror("sem_open queue_empty fail!\n");
        exit(EXIT_FAILURE);
    }
    sem_queue_full = sem_open(queue_full, O_CREAT, 0644, 0);
    if (sem_queue_full == SEM_FAILED)
    {
        perror("sem_open queue_full fail!\n");
        exit(EXIT_FAILURE);
    }

    // 读写指针初始化，开始时都指向第0行
    shared_stuff->line_write = 0;
    shared_stuff->line_read = 0;

    // 不断从控制台读入按键输入的字符行
    while (1)
    {
        printf("Enter your text('quit' for exit): ");
        fgets(key_line, sizeof(key_line), stdin); // gets被认作不安全

        // 将输入的行写入缓冲区，要有信号量操作
        sem_wait(sem_queue_empty); // 等待空缓冲区信号量
        sem_wait(sem_queue);       // 进入临界区

        strncpy(shared_stuff->buffer[shared_stuff->line_write], key_line, LINE_SIZE);
        shared_stuff->line_write = (shared_stuff->line_write + 1) % NUM_LINE;

        sem_post(sem_queue);      // 离开临界区
        sem_post(sem_queue_full); // 发布满缓冲区信号量

        if (!strcmp(key_line, "quit\n"))
        {
            break;
        }
    }

    // 因键入“quit”从前面while()循环中跳到此处，程序退出前，释放信号量
    // 释放信号量，结束共享内存在本进程的挂在映像，删除共享内存区域
    sem_close(sem_queue);
    sem_close(sem_queue_empty);
    sem_close(sem_queue_full);
    sem_unlink(queue_mutex);
    sem_unlink(queue_empty);
    sem_unlink(queue_full);
    shmdt(shared_memory);
    shmctl(shmid, IPC_RMID, NULL);
}